package com.wry.service.impl;

import com.wry.model.Order;
import com.wry.repository.OrderRepository;
import com.wry.service.OrderService;
import com.wry.utils.PageResponse;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <h1>  <h1>
 *
 * @author wry
 * @since 2023/8/21 11:19
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Resource
    private OrderRepository orderRepository;
    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public void saveAll(List<Order> orders) {
        orders.forEach(order -> {
            if (order.getCreateAt() == null){
                order.setCreateAt(LocalDateTime.now());
            }
        });
        orderRepository.saveAll(orders);
    }

    @Override
    public void deleteById(Integer id) {
        orderRepository.deleteById(id);
    }

    @Override
    public void updateById(Order order) {
        orderRepository.save(order);
    }

    @Override
    public PageResponse<Order> findList(Order order, Integer pageIndex, Integer pageSize) {
        CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria()
                .and(new Criteria("orderDesc").contains(order.getOrderDesc()))
                .and(new Criteria("orderNo").is(order.getOrderNo())))
                .setPageable(PageRequest.of(pageIndex, pageSize));

        SearchHits<Order> searchHits = elasticsearchRestTemplate.search(criteriaQuery, Order.class);
        List<Order> result = searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
        PageResponse<Order> pageResponse = new PageResponse<Order>();
        pageResponse.setTotal(searchHits.getTotalHits());
        pageResponse.setResult(result);
        return pageResponse;
    }

    @Override
    public PageResponse<Order> findListByName(String userName, Integer pageIndex, Integer pageSize) {
        // 根据username模糊分页匹配
        final WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("username.keyword", ("*" + userName + "*"));
        //final QueryStringQueryBuilder likeQ2 = QueryBuilders.queryStringQuery(userName).field("username");
        // 多个字段模糊匹配
        //final MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(userName, "username", "orderDesc");
        final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(wildcardQueryBuilder)
                .build();
        final SearchHits<Order> searchHits = elasticsearchRestTemplate.search(searchQuery, Order.class);
        final List<Order> orderList = searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
        PageResponse<Order> pageResponse = new PageResponse<>();
        pageResponse.setTotal(searchHits.getTotalHits());
        pageResponse.setResult(orderList);
        return pageResponse;
    }

    @Override
    public PageResponse<Order> findAll(Integer pageIndex, Integer pageSize) {
        Page<Order> page = orderRepository.findAll(PageRequest.of(pageIndex, pageSize));
        PageResponse<Order> pageResponse = new PageResponse<Order>();
        pageResponse.setTotal(page.getTotalElements());
        pageResponse.setResult(page.getContent());
        return pageResponse;
    }

    @Override
    public PageResponse<Order> findHighlight(Order order, Integer pageIndex, Integer pageSize) {
        if (order == null) {
            PageResponse<Order> pageResponse = new PageResponse<Order>();
            pageResponse.setTotal(0L);
            pageResponse.setResult(new ArrayList<>());
            return pageResponse;
        }

        CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria()
                .and(new Criteria("orderNo").is(order.getOrderNo()))
                .and(new Criteria("orderDesc").contains(order.getOrderDesc())))
                .setPageable(PageRequest.of(pageIndex, pageSize));

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("orderNo").field("orderDesc");
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.preTags("<h3 style=color:blue >");
        highlightBuilder.postTags("</h3>");

        HighlightQuery highlightQuery = new HighlightQuery(highlightBuilder);
        criteriaQuery.setHighlightQuery(highlightQuery);

        SearchHits<Order> searchHits = elasticsearchRestTemplate.search(criteriaQuery, Order.class);

        List<Order> result = searchHits.get().map(e -> {
            Order element = e.getContent();
            element.setHighlights(e.getHighlightFields());
            return element;
        }).collect(Collectors.toList());

        PageResponse<Order> pageResponse = new PageResponse<Order>();
        pageResponse.setTotal(searchHits.getTotalHits());
        pageResponse.setResult(result);
        return pageResponse;
    }

    @Override
    public Order findById(Integer id) {
        return orderRepository.findById(id).orElse(null);
    }

    @Override
    public PageResponse<Order> rangeQueryByOrderNo(Long startNo, Long endNo, Integer pageIndex, Integer pageSize) {
        // 范围分页查询 [gte >=] [lte <=] [gt >] [lt <]
        final RangeQueryBuilder rangeQueryBuilder = new RangeQueryBuilder("orderNo").gte(startNo).lte(endNo);
        final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(rangeQueryBuilder)
                .build();
        final SearchHits<Order> searchHits = elasticsearchRestTemplate.search(searchQuery, Order.class);
        return PageResponse.page(searchHits);
    }

    @Override
    public PageResponse<Order> rangeQueryByTime(String startTime, String endTime, Integer pageIndex, Integer pageSize) {
        final RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("createAt")
                .format("yyyy-MM-dd HH:mm:ss")
                .gte(startTime)
                .lte(endTime)
                .includeLower(true)
                .includeUpper(true);
        final NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(rangeQueryBuilder)
                .build();
        final SearchHits<Order> searchHits = elasticsearchRestTemplate.search(searchQuery, Order.class);
        return PageResponse.page(searchHits);
    }
}
